using System;
using System.Security;
using System.Security.Principal;
using Be.Timvw.Framework.Win32;
using Be.Timvw.Framework.Win32.SafeHandles;

namespace Be.Timvw.Framework.Security.Principal
{
    public class WindowsIdentityHelper : IDisposable
    {
        private readonly SafeTokenHandle userTokenHandle;
        private bool isDisposed;

        public WindowsIdentityHelper(string username, string domain, SecureString password)
        : this(username, domain, password, LogonType.Interactive)
        {
        }

        public WindowsIdentityHelper(string username, string domain, SecureString password, LogonType logonType)
        : this(username, domain, password, logonType, LogonProvider.Default)
        {
        }

        public WindowsIdentityHelper(string username, string domain, SecureString password, LogonType logonType, LogonProvider logonProvider)
        {
            using(SafeGlobalAllocUnicodeHandle passwordHandle = new SafeGlobalAllocUnicodeHandle(password))
            {
                if(!NativeMethods.LogonUser(username, domain, passwordHandle, logonType, logonProvider, out this.userTokenHandle))
                {
                    throw new ArgumentException("Could not acquire UserToken.");
                }
            }
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        public WindowsIdentity GetWindowsIdentity()
        {
            if(this.isDisposed)
            {
                throw new ArgumentException("WindowsIdentityHelper is already disposed.");
            }

            return new WindowsIdentity(this.userTokenHandle.DangerousGetHandle());
        }

        ~WindowsIdentityHelper()
        {
            this.Dispose(false);
        }

        protected virtual void Dispose(bool isDisposing)
        {
            if(!this.isDisposed)
            {
                if(isDisposing)
                {
                    this.userTokenHandle.Dispose();
                }

                this.isDisposed = true;
            }
        }
    }
}